#include "unp.h"

#define CONTROL_LEN  (sizeof(struct cmsghdr) + sizeof(struct ucred))

ssize_t read_fd(int fd, void* pbuff,struct ucred* cmsgcredptr);

int main(int argc, char **argv)
{
  int sockfd,n,optval;
  char buf[512] = {'\0'};
  struct sockaddr_un servaddr;
  struct ucred cred;

  if (argc != 2)
  {
    printf("usage : domaincli <filepath>\n");
    exit(-1);
  }

  memset(&servaddr, 0,sizeof(servaddr));
  sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);

  servaddr.sun_family = AF_LOCAL;
  strcpy(servaddr.sun_path, argv[1]);
  setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval));
  connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr));
  optval = 1;
  
  while ( (n = read_fd(sockfd,buf,&cred)) > 0)
  {
    buf[n] = '\0';
    printf("Recv_msg from server: %s\n",buf);
    printf("uid is:%d\n",cred.uid);
    printf("gid is:%d\n",cred.gid);
    printf("pid is:%d\n",cred.pid);
  }

  return 0;
}

ssize_t read_fd(int fd, void* pbuff,struct ucred* cmsgcredptr)
{
  struct msghdr msg;
  struct iovec  iov[3];
  struct cmsghdr *cmptr;
 
  char buf1[3],buf2[3],buf3[4];
  char control[CONTROL_LEN];
  int n;
  
  union 
  {
    struct cmsghdr cmh;
    char   control[CMSG_SPACE(sizeof(struct ucred))];    
  } control_un;

  memset(&msg,0,sizeof(msg));
  iov[0].iov_base = buf1;
  iov[0].iov_len = 3;
  iov[1].iov_base = buf2;
  iov[1].iov_len = 3;
  iov[2].iov_base = buf3;
  iov[2].iov_len = 3;

  msg.msg_name        = NULL;
  msg.msg_namelen     = 0;
  msg.msg_iov         = iov;
  msg.msg_iovlen      = 3;
  msg.msg_control     = NULL;
  msg.msg_control     = control_un.control;
  msg.msg_controllen  = sizeof(control_un.control);
  
  n = recvmsg(fd, &msg, 0); // After the line, msg.msg_controllen is reset = 0. WHY?

  cmptr = (struct cmsghdr *) msg.msg_control;
  if (cmptr->cmsg_type == SCM_CREDENTIALS)
    printf("match the cred level\n");
  
  memcpy(cmsgcredptr, CMSG_DATA(cmptr), sizeof(struct ucred));

  memcpy(pbuff,buf1,sizeof(buf1)); 
  memcpy(pbuff+sizeof(buf1),buf2,sizeof(buf2));
  memcpy(pbuff+sizeof(buf1) + sizeof(buf2),buf3,sizeof(buf3));
 
  return n;
}
